package com.wkck.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wkck.VO.CareerListDetails;
import com.wkck.VO.NewsInfoVO;
import com.wkck.VO.PageResult;
import com.wkck.VO.UploadContentVo;
import com.wkck.context.BaseContext;
import com.wkck.domain.News;
import com.wkck.domain.NewsContent;
import com.wkck.domain.NewsPhotos;
import com.wkck.dto.NewsQueryBackendDto;
import com.wkck.dto.NewsQueryFrontendDto;
import com.wkck.dto.SaveNewsInfoDto;
import com.wkck.exception.BaseException;
import com.wkck.exception.FileNotFoundException;
import com.wkck.exception.UploadErrorException;
import com.wkck.mapper.NewsContentMapper;
import com.wkck.mapper.NewsMapper;
import com.wkck.mapper.NewsPhotosMapper;
import com.wkck.service.NewsService;
import com.wkck.utils.DateTimeGeneration;
import io.minio.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

@Service
@Slf4j
public class NewsServiceImpl extends ServiceImpl<NewsMapper, News> implements NewsService {

    @Resource
    private NewsMapper newsMapper;

    @Autowired
    private NewsContentMapper contentMapper;

    @Autowired
    private NewsPhotosMapper photosMapper;

    private static final String photoBucket = "news";

    @Value("${minio.endpoint}")
    private String endpoint;

    @Autowired
    private MinioClient minioClient;

    @Override
    public PageResult getNewsInfo(NewsQueryBackendDto dto) {

        PageHelper.startPage(dto.getCurrentPage(),dto.getSize());

        Page<News> newsList = newsMapper.getNewsList(dto);

        return new PageResult(newsList.getTotal(),newsList.getResult());
    }

    @Override
    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<News> getFrontendNewsInfo(NewsQueryFrontendDto dto) {

        com.baomidou.mybatisplus.extension.plugins.pagination.Page<News> page = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(dto.getCurrentPage(), dto.getSize());

        LambdaQueryWrapper<News> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(News::getIs_deleted, 0);

        return newsMapper.selectPage(page, queryWrapper);
    }

    /***
     * @Author: CK
     * @Date: 2024/3/21
     * @Param: []
     * @Description: 创建新闻数据记录
     */
    @Override
    @Transactional
    public String createNewsInfo() {
        long articleId = IdWorker.getId();
        News news = News.builder()
                .id(articleId)
                .read_num(0)
                .is_deleted(1)
                .build();

        newsMapper.insert(news);

        NewsContent content = NewsContent.builder()
                .news_id(articleId)
                .build();
        contentMapper.insert(content);

//        NewsPhotos photo = NewsPhotos.builder()
//                .news_id(articleId)
//                .create_time(DateTimeGeneration.now())
//                .create_user(BaseContext.getCurrentId().intValue())
//                .build();
//
//        photosMapper.insert(photo);

        log.info("数据插入成功");
        return String.valueOf(articleId);
    }

    /***
     * @Author: CK
     * @Date: 2024/3/21
     * @Param: [id]
     * @Description: 根据新闻id得到新闻信息
     */
    @Override
    public NewsInfoVO getNewsInfoById(Long id) {

        if (id == null) {
            throw new BaseException("编号异常 拒绝操作！");
        }

        NewsInfoVO news = newsMapper.getNewsInfoById(id);

        // 使文章的阅读次数 ++
        LambdaUpdateWrapper<News> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(News::getRead_num, news.getRead_num() + 1)
                .eq(News::getId, news.getId());

        newsMapper.update(news, updateWrapper);

        return news;
    }

    /***
     * @Author: CK
     * @Date: 2024/3/22
     * @Param: [file, id]
     * @Description: 新闻添加封面图
     */
    @Override
    public String insertNewsTitlePhotoById(String localFilePath, long size, String filename, Long id) {
        File file = new File(localFilePath);

        if (!file.exists()) {
            throw new FileNotFoundException("文件未找到，上传失败!");
        }

        if (id == null) {
            throw new BaseException("编号为空 不允许添加封面!");
        }

        LambdaQueryWrapper<News> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(News::getId, id);
        News news = newsMapper.selectOne(queryWrapper);
        if (Objects.isNull(news)) {
            throw new BaseException("无对应新闻信息 不允许添加封面!");
        }

        String pre = id + "/cover";

        String location = pre + "/" + filename;

        if (Strings.isNotEmpty(news.getTitle_picture())) {

            String new_location = news.getTitle_picture().replaceFirst(photoBucket + "/", "");
            try {
                minioClient.removeObject(
                        RemoveObjectArgs.builder()
                                .bucket(photoBucket)
                                .object(new_location)
                                .build()
                );
            } catch (Exception e) {
                throw new BaseException("minio文件删除失败");
            }
        }

        try {
            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(photoBucket)
                            .object(location)
                            .filename(localFilePath)
                            .build());
            log.info("封面上传成功, {}", location);
        } catch (Exception e) {
            throw new UploadErrorException("封面上传失败");
        }

        String db_location = photoBucket + "/" + location;

        LambdaUpdateWrapper<News> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(News::getTitle_picture, db_location)
                .eq(News::getId, id);

        newsMapper.update(news, updateWrapper);

        return db_location;
    }

    /**
     * @Author: CK
     * @Date: 2024/3/22
     * @Param: [id]
     * @Description: 删除新闻
     */
    @Override
    @Transactional
    public Boolean removeNewsById(List<String> ids) {
        if (ids.isEmpty()) {
            throw new BaseException("编号为空 不允许操作!");
        }

        newsMapper.deleteBatchIds(ids);

        contentMapper.deleteByNewId(ids);

        photosMapper.deleteByNewId(ids);

        List<NewsPhotos> newsPhotos = photosMapper.selectBatchIds(ids);
        for (NewsPhotos newsPhoto : newsPhotos) {
            try {
                minioClient.removeObject(
                        RemoveObjectArgs.builder()
                                .bucket(newsPhoto.getBucket())
                                .object(newsPhoto.getLocation())
                                .build()
                );
            } catch (Exception e) {
                throw new BaseException("minio文件删除失败");
            }
        }

        return true;
    }

    /***
     * @Author: CK
     * @Date: 2024/3/22
     * @Param: [file, id]
     * @Description: 上传正文中图片
     */
    @Override
    public UploadContentVo uploadContentPhoto(String localFilePath, long size, String filename, Long id) {
        File file = new File(localFilePath);

        if (!file.exists()) {
            throw new FileNotFoundException("文件未找到，上传失败!");
        }

        if (id == null) {
            throw new BaseException("编号为空 不允许添加正文图片!");
        }

        String location = id + "/content/" + UUID.randomUUID() + filename;

        try {
            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(photoBucket)
                            .object(location)
                            .filename(localFilePath)
                            .build());
            log.info("正文图片上传成功, {}", location);
        } catch (Exception e) {
            throw new UploadErrorException("正文图片上传失败");
        }

        NewsPhotos photo = NewsPhotos.builder()
                .file_name(filename)
                .bucket(photoBucket)
                .size(String.valueOf(size))
                .location(location)
                .news_id(id)
                .create_time(DateTimeGeneration.now())
                .create_user(BaseContext.getCurrentId().intValue())
                .build();

        photosMapper.insert(photo);

        return UploadContentVo.builder()
                .bucket(photoBucket)
                .file_name(filename)
                .url(location)
                .build();
    }

    /***
     * @Author: CK
     * @Date: 2024/3/23
     * @Param: [dto]
     * @Description: 保存新闻信息
     */
    @Override
    @Transactional
    public Boolean saveNewsInfo(SaveNewsInfoDto dto) {
        if (Objects.isNull(dto)) {
            throw new BaseException("数据为空 禁止发布！");
        }

        if (dto.getTitle().length() < 10 || dto.getTitle().length() > 40) {
            throw new BaseException("标题不符合要求 请重新输入！");
        }

        LambdaUpdateWrapper<News> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(News::getTitle, dto.getTitle())
                .set(News::getSub_title, dto.getSub_title())
                .set(News::getIssuer, BaseContext.getCurrentId().intValue())
                .set(News::getIssue_time, DateTimeGeneration.now())
                .set(News::getIs_deleted, dto.getIs_deleted())
                .eq(News::getId, dto.getId());

        News news = new News();
        BeanUtils.copyProperties(dto, news);

        newsMapper.update(news, updateWrapper);

        LambdaUpdateWrapper<NewsContent> contentWrapper = new LambdaUpdateWrapper<>();
        contentWrapper
                .set(NewsContent::getContent, dto.getContent())
                        .eq(NewsContent::getNews_id, dto.getId());

        NewsContent content = NewsContent.builder()
                .news_id(dto.getId())
                .content(dto.getContent())
                .build();

        contentMapper.update(content, contentWrapper);

        return true;
    }

    /****
     * @Author: CK
     * @Date: 2024/3/23
     * @Param: [news]
     * @Description: 修改新闻状态
     */
    @Override
    public Boolean changeState(News news) {
        if (Objects.isNull(news)) {
            throw new BaseException("信息为空 修改失败!");
        }

        LambdaUpdateWrapper<News> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .set(News::getIs_deleted, news.getIs_deleted())
                .eq(News::getId, news.getId());

        newsMapper.update(news, updateWrapper);

        return true;
    }

    /***
     * @Author: CK
     * @Date: 2024/3/23
     * @Param: [id]
     * @Description: 预览新闻
     */
    @Override
    public NewsContent getPreviewNewsContent(Long id) {
        if (id == null || String.valueOf(id).equals("undefined")) {
            throw new BaseException("编号为空 不允许预览");
        }

        LambdaQueryWrapper<NewsContent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(NewsContent::getNews_id, id);

        return contentMapper.selectOne(queryWrapper);
    }

    private void deleteMinioNewsInfo(String bucket, String folder) {

    }
}
